# coding=UTF-8
from core_model import Core
from common_model import Common
import numpy as np
import random

# 描述块的类
class Block:
	# 参数
	dimension = Common.BLOCK_dimension # 维度
	size = Common.BLOCK_size # 每个维度的大小
	# 类型
	# 块有三种类型，分别为生：0，死：1，无：2，金：3
	LIVE = Common.BLOCK_LIVE
	DEAD = Common.BLOCK_DEAD
	NONE = Common.BLOCK_NONE
	GOLD = Common.BLOCK_GOLD

	# 初始化
	def __init__(self, rich, b_i, b_j, grid_io):
		# 定义脑的变量
		self.dimension = Common.BLOCK_dimension # 维度
		self.size = Common.BLOCK_size # 每个维度的大小
		self.connect = [] # 拥有的虚空连接，只记录出去的虚空连接
		self.grid_io = grid_io # 写入读取格的函数，包括通的实现
		# 初始化块中所有格
		grid = [] # [[息, 素], ...]
		for i in range(pow(Block.size, Block.dimension)):
			grid.append([random.random() * 2.0 - 1.0, random.random() * 2.0 - 1.0])
		self.grid = grid
		# 定义块的类型
		self.type = Block.NONE
		if random.random() > rich: # rich在0到1之间，越大越富有，死越少
			self.type = Block.DEAD
		# 块的位置
		self.b_i = b_i
		self.b_j = b_j
		# 拥有的核
		self.core_list = []
		# 存活时长
		self.time = 0 # 初始寿命
		self.score = 0 # 分数
		# 拥有的神赐之种数量
		self.seed_num = 0
		# 最大尺寸（节约计算量）
		self.max_size = pow(self.size, self.dimension)
		# # 刻印
		# self.max_scar_length = Common.BLOCK_size * Common.BLOCK_dimension # 最大刻印长度
		# self.scar_func_type_num = 7 # 刻印功能数量
		# self.scar_func_num = 4 * self.scar_func_type_num # 单长度刻印数量
		# self.scar = [] # 刻印是三维列表，第一维是刻印长度，第二维是刻印功能，第三维存放刻印本身
		# for i in range(self.max_scar_length):
		# 	one_scar = []
		# 	for j in range(self.scar_func_num):
		# 		one_one_scar = []
		# 		for k in range(i):
		# 			one_one_scar.append(random.random() * 2.0 - 1.0) # 取值范围(-1, 1)
		# 		one_scar.append(np.array(one_one_scar))
		# 	self.scar.append(one_scar)

	# 拷贝
	def copy(source, dest):
		# 拷贝格、类型、核、分数、存活时长、位置
		# 格
		for i in range(len(source.grid)):
			dest.grid[i][0] = source.grid[i][0]
			dest.grid[i][1] = source.grid[i][1]
		# 类型
		dest.type = source.type
		# 核
		dest.core_list = [] # 清空
		for i in range(len(source.core_list)):
			core_ = Core(dest)
			core_.place = source.core_list[i].place
			core_.vector = source.core_list[i].vector	
		dest.score = source.score # 分数
		dest.time = source.time # 存活时长
		# 块的位置
		dest.b_i = source.b_i
		dest.b_j = source.b_j
		# # 拷贝刻印
		# for i in range(len(source.scar)):
		# 	for j in range(len(source.scar[i])):
		# 		for k in range(i):
		# 			dest.scar[i][j][k] = source.scar[i][j][k]

	# 清理核
	def clean(self):
		block_dic = {} # 块字典
		core_block_num = [] # 核所属块编号表
		for i in range(len(self.core_list)):
			if self.core_list[i].place_block not in block_dic:
				block_dic[self.core_list[i].place_block] = len(block_dic)
			core_block_num.append(block_dic[self.core_list[i].place_block])
		# 计算最大取值
		max_size = self.max_size
		# 1、核的凋亡判定（控制核的密度，限制运算量）
		# 1.1 如果【核的向量】存在核，则位于【核的向量】的核凋亡（这一步同时清理长度为0的核）
		# 以核的位置为索引建立倒排索引表
		place_dic = {} # {核的位置: 核序号, ...}
		for i in range(len(self.core_list)):
			index = core_block_num[i] * max_size + self.core_list[i].place
			if index not in place_dic:
				place_dic[index] = [i]
			else:
				place_dic[index].append(i)
		# 所有被核指向的核凋亡
		for i in range(len(self.core_list)):
			index = core_block_num[i] * max_size + self.core_list[i].vector
			if index not in place_dic:
				continue
			clean_list = place_dic[index] # 清理列表
			# 清理列表中的核凋亡
			for j in range(len(clean_list)):
				self.core_list[clean_list[j]].place = -1
				self.core_list[clean_list[j]].vector = -1
			place_dic.pop(index) # 不需要重复清除
		# 1.2 如果出现重叠（【核的坐标】、【核的向量】都相同）的核，只保留其中一个
		# 以核的位置以及核的向量为索引建立倒排索引表
		place_vector_dic = {} # {核的位置 * 最大取值 + 核的向量: 核序号, ...}
		for i in range(len(self.core_list)):
			dic_key = core_block_num[i] * max_size * max_size + self.core_list[i].place * max_size + self.core_list[i].vector
			if dic_key not in place_vector_dic:
				place_vector_dic[dic_key] = [i]
			else: # 存在重叠的核，该核凋亡
				self.core_list[i].place = -1
				self.core_list[i].vector = -1
		# 2、清理所有凋亡的核
		for i in range(len(self.core_list) - 1, -1, -1):
			if self.core_list[i].place == -1: # 如果核的坐标为-1，核凋亡
				self.core_list.pop(i)
		# 3、如果生不再拥有核，生变为无
		if len(self.core_list) == 0:
			self.type = Common.BLOCK_NONE

